module mycpu_top(
    input  wire        clk,
    input  wire        resetn,
    // inst sram interface
    output        inst_sram_en,
    output wire [ 3:0] inst_sram_we,
    output wire [31:0] inst_sram_addr,
    output wire [31:0] inst_sram_wdata,
    input  wire [31:0] inst_sram_rdata,
    // data sram interface
    output        data_sram_en,
    output wire [ 3:0] data_sram_we,    
    output wire [31:0] data_sram_addr,
    output wire [31:0] data_sram_wdata,
    input  wire [31:0] data_sram_rdata,
    // trace debug interface
    output wire [31:0] debug_wb_pc,
    output wire [ 3:0] debug_wb_rf_we,
    output wire [ 4:0] debug_wb_rf_wnum,
    output wire [31:0] debug_wb_rf_wdata
);
wire         reset;
assign reset = ~resetn;

reg fs_valid;
reg ds_valid;
reg es_valid;
reg ms_valid;
reg ws_valid;

wire fs_ready_go;
wire ds_ready_go;
wire es_ready_go;
wire ms_ready_go;
wire ws_ready_go;

wire fs_allowin;
wire ds_allowin;
wire es_allowin;
wire ms_allowin;
wire ws_allowin;

wire to_fs_valid;
wire fs_to_ds_valid;
wire ds_to_es_valid;
wire es_to_ms_valid;
wire ms_to_ws_valid;

wire [31:0] seq_pc;
wire [31:0] nextpc;
wire        br_taken;
wire [31:0] br_target;
wire [31:0] inst;
reg  [31:0] pc;

wire [11:0] alu_op;
wire        load_op;
wire        src1_is_pc;
wire        src2_is_imm;
wire        res_from_mem;
wire        dst_is_r1;
wire        gr_we;
wire        mem_we;
wire        src_reg_is_rd;
wire [4: 0] dest;
wire [31:0] rj_value;
wire [31:0] rkd_value;
wire [31:0] imm;
wire [31:0] br_offs;
wire [31:0] jirl_offs;

wire [ 5:0] op_31_26;
wire [ 3:0] op_25_22;
wire [ 1:0] op_21_20;
wire [ 4:0] op_19_15;
wire [ 4:0] rd;
wire [ 4:0] rj;
wire [ 4:0] rk;
wire [11:0] i12;
wire [19:0] i20;
wire [15:0] i16;
wire [25:0] i26;

wire [63:0] op_31_26_d;
wire [15:0] op_25_22_d;
wire [ 3:0] op_21_20_d;
wire [31:0] op_19_15_d;

wire        inst_add_w;
wire        inst_sub_w;
wire        inst_slt;
wire        inst_sltu;
wire        inst_nor;
wire        inst_and;
wire        inst_or;
wire        inst_xor;
wire        inst_slli_w;
wire        inst_srli_w;
wire        inst_srai_w;
wire        inst_addi_w;
wire        inst_ld_w;
wire        inst_st_w;
wire        inst_jirl;
wire        inst_b;
wire        inst_bl;
wire        inst_beq;
wire        inst_bne;
wire        inst_lu12i_w;
wire        inst_slti;
wire        inst_sltui;
wire        inst_andi;
wire        inst_ori;
wire        inst_xori;
wire        inst_sll;
wire        inst_srl;
wire        inst_sra;
wire        inst_pcaddu12i;
wire        inst_mul_w;
wire        inst_mulh_w;
wire        inst_mulh_wu;
wire        inst_div_w;
wire        inst_mod_w;
wire        inst_div_wu;
wire        inst_mod_wu;

wire        need_ui5;
wire        need_si12;
wire        need_si16;
wire        need_si20;
wire        need_si26;
wire        src2_is_4;
wire        need_si12_zero;

wire [ 4:0] rf_raddr1;
wire [31:0] rf_rdata1;
wire [ 4:0] rf_raddr2;
wire [31:0] rf_rdata2;
wire        rf_we   ;
wire [ 4:0] rf_waddr;
wire [31:0] rf_wdata;

wire [31:0] alu_src1   ;
wire [31:0] alu_src2   ;
wire [31:0] alu_result ;

wire [31:0] es_alu_result;
wire [31:0] ms_result;
wire [31:0] ms_final_result;

reg [31:0] ds_pc;
reg [31:0] ds_inst;//regs in ID

reg [11:0] es_alu_op ;
reg es_res_from_mem;
reg         es_gr_we;
reg         es_mem_we;
reg  [ 4:0] es_dest;
reg  [31:0] es_rj_value;
reg  [31:0] es_rkd_value;
reg  [31:0] es_pc;
reg  [31:0] es_alu_src1;
reg  [31:0] es_alu_src2;//regs in EXE

reg ms_res_from_mem;
reg [31:0] ms_alu_result;
reg ms_gr_we;
reg [ 4:0] ms_dest;
reg [31:0] ms_pc;//regs in MEM

reg ws_gr_we;
reg [ 4:0] ws_dest;
reg [31:0] ws_final_result;
reg [31:0] ws_pc;//regs in WB

wire es_rf_we;
wire ms_rf_we;
wire ws_rf_we;

//IF stage

assign to_fs_valid = ~reset;
assign fs_ready_go = 1'b1;
assign fs_allowin = (~fs_valid) | (fs_ready_go & ds_allowin);
assign fs_to_ds_valid = fs_valid & fs_ready_go;
    //pre-IF
assign seq_pc       = pc + 3'h4;
assign nextpc       = br_taken ? br_target : seq_pc;

always @(posedge clk) begin
    if (reset) begin
        pc <= 32'h1bfffffc; 
    end
    else if(to_fs_valid & fs_allowin) begin
        pc <= nextpc;
    end
end

always @(posedge clk ) begin
    if (reset) begin
        fs_valid <= 1'b0;
    end
    else if (fs_allowin) begin
        fs_valid <= to_fs_valid;
    end
    else if(br_taken)begin
        fs_valid <= 1'b0;
    end
end
assign inst_sram_en    = to_fs_valid && fs_allowin;
assign inst_sram_we    = 4'b0000;
assign inst_sram_addr  = nextpc;
assign inst_sram_wdata = 32'b0;
assign inst            = inst_sram_rdata;

//ID stage
wire read_rd;
wire read_rj;
wire read_rk;
wire rd_conflict;
wire rj_conflict;
wire rk_conflict;
wire [2:0] read_after_write_addr1;
wire [2:0] read_after_write_addr2;
always @(posedge clk ) begin//ID reg
    if (fs_to_ds_valid & ds_allowin) begin
        ds_inst <= inst;
        ds_pc <= pc; 
    end
end

assign read_rk = inst_add_w | inst_sub_w | inst_slt | inst_sltu | inst_and | inst_or | inst_nor | inst_xor 
                | inst_sll | inst_srl | inst_sra 
                | inst_mul_w | inst_mulh_w | inst_mulh_wu | inst_div_w | inst_div_wu | inst_mod_w | inst_mod_wu;

assign read_rj = ~inst_lu12i_w & ~inst_b & ~inst_bl & ~inst_pcaddu12i;
assign read_rd = inst_beq | inst_bne | inst_st_w;

assign rk_conflict = (rk != 5'b0)  
    & read_rk 
    & (es_rf_we & (es_dest == rk)
    | ms_rf_we & (ms_dest == rk)
    | ws_rf_we & (ws_dest == rk));

assign rj_conflict = (rj != 5'b0)  
    & read_rj 
    &(es_rf_we & (es_dest == rj)
    | ms_rf_we & (ms_dest == rj)
    | ws_rf_we & (ws_dest == rj));

assign rd_conflict = (rd != 5'b0)  
    & read_rd 
    &(es_rf_we & (es_dest == rd)
    | ms_rf_we & (ms_dest == rd)
    | ws_rf_we & (ws_dest == rd));

assign ds_ready_go = !( (read_after_write_addr1[2]) && es_res_from_mem) ;
assign ds_allowin = (~ds_valid) | (ds_ready_go & es_allowin);
assign ds_to_es_valid = ds_valid & ds_ready_go;

assign read_after_write_addr1 = {3{read_rj&&(rf_raddr1!=5'b0)}}&{ (es_rf_we)&&(es_dest ==rf_raddr1),
                                                                       (ms_rf_we)&&(ms_dest ==rf_raddr1),
                                                                       (ws_rf_we   )&&(ws_dest==rf_raddr1)};
assign read_after_write_addr2 = {3{(read_rd || read_rk)&&rf_raddr2!=5'b0}}&{ (es_rf_we)&&(es_dest ==rf_raddr2),
                                                                       (ms_rf_we)&&(ms_dest ==rf_raddr2),
                                                                       (ws_rf_we   )&&(ws_dest==rf_raddr2)};

always @(posedge clk ) begin
    if (reset) begin
        ds_valid <= 1'b0;
    end
    else if(br_taken)begin
        ds_valid <= 1'b0;
    end
    else if (ds_allowin) begin
        ds_valid <= fs_to_ds_valid;
    end
end
assign op_31_26  = ds_inst[31:26];
assign op_25_22  = ds_inst[25:22];
assign op_21_20  = ds_inst[21:20];
assign op_19_15  = ds_inst[19:15];

assign rd   = ds_inst[ 4: 0];
assign rj   = ds_inst[ 9: 5];
assign rk   = ds_inst[14:10];

assign i12  = ds_inst[21:10];
assign i20  = ds_inst[24: 5];
assign i16  = ds_inst[25:10];
assign i26  = {ds_inst[ 9: 0], ds_inst[25:10]};

decoder_6_64 u_dec0(.in(op_31_26 ), .out(op_31_26_d ));
decoder_4_16 u_dec1(.in(op_25_22 ), .out(op_25_22_d ));
decoder_2_4  u_dec2(.in(op_21_20 ), .out(op_21_20_d ));
decoder_5_32 u_dec3(.in(op_19_15 ), .out(op_19_15_d ));

assign inst_add_w  = op_31_26_d[6'h00] & op_25_22_d[4'h0] & op_21_20_d[2'h1] & op_19_15_d[5'h00];
assign inst_sub_w  = op_31_26_d[6'h00] & op_25_22_d[4'h0] & op_21_20_d[2'h1] & op_19_15_d[5'h02];
assign inst_slt    = op_31_26_d[6'h00] & op_25_22_d[4'h0] & op_21_20_d[2'h1] & op_19_15_d[5'h04];
assign inst_sltu   = op_31_26_d[6'h00] & op_25_22_d[4'h0] & op_21_20_d[2'h1] & op_19_15_d[5'h05];
assign inst_nor    = op_31_26_d[6'h00] & op_25_22_d[4'h0] & op_21_20_d[2'h1] & op_19_15_d[5'h08];
assign inst_and    = op_31_26_d[6'h00] & op_25_22_d[4'h0] & op_21_20_d[2'h1] & op_19_15_d[5'h09];
assign inst_or     = op_31_26_d[6'h00] & op_25_22_d[4'h0] & op_21_20_d[2'h1] & op_19_15_d[5'h0a];
assign inst_xor    = op_31_26_d[6'h00] & op_25_22_d[4'h0] & op_21_20_d[2'h1] & op_19_15_d[5'h0b];
assign inst_slli_w = op_31_26_d[6'h00] & op_25_22_d[4'h1] & op_21_20_d[2'h0] & op_19_15_d[5'h01];
assign inst_srli_w = op_31_26_d[6'h00] & op_25_22_d[4'h1] & op_21_20_d[2'h0] & op_19_15_d[5'h09];
assign inst_srai_w = op_31_26_d[6'h00] & op_25_22_d[4'h1] & op_21_20_d[2'h0] & op_19_15_d[5'h11];
assign inst_addi_w = op_31_26_d[6'h00] & op_25_22_d[4'ha];
assign inst_ld_w   = op_31_26_d[6'h0a] & op_25_22_d[4'h2];
assign inst_st_w   = op_31_26_d[6'h0a] & op_25_22_d[4'h6];
assign inst_jirl   = op_31_26_d[6'h13];
assign inst_b      = op_31_26_d[6'h14];
assign inst_bl     = op_31_26_d[6'h15];
assign inst_beq    = op_31_26_d[6'h16];
assign inst_bne    = op_31_26_d[6'h17];
assign inst_lu12i_w= op_31_26_d[6'h05] & ~ds_inst[25];
assign inst_slti   = op_31_26_d[6'h00] & op_25_22_d[4'h8];
assign inst_sltui  = op_31_26_d[6'h00] & op_25_22_d[4'h9];
assign inst_andi   = op_31_26_d[6'h00] & op_25_22_d[4'hd];
assign inst_ori    = op_31_26_d[6'h00] & op_25_22_d[4'he];
assign inst_xori   = op_31_26_d[6'h00] & op_25_22_d[4'hf];
assign inst_sll    = op_31_26_d[6'h00] & op_25_22_d[4'h0] & op_21_20_d[2'h1] & op_19_15_d[5'h0e];
assign inst_srl    = op_31_26_d[6'h00] & op_25_22_d[4'h0] & op_21_20_d[2'h1] & op_19_15_d[5'h0f];
assign inst_sra    = op_31_26_d[6'h00] & op_25_22_d[4'h0] & op_21_20_d[2'h1] & op_19_15_d[5'h10];
assign inst_pcaddu12i= op_31_26_d[6'h07];
assign inst_mul_w  = op_31_26_d[6'h00] & op_25_22_d[4'h0] & op_21_20_d[2'h1] & op_19_15_d[5'h18];
assign inst_mulh_w = op_31_26_d[6'h00] & op_25_22_d[4'h0] & op_21_20_d[2'h1] & op_19_15_d[5'h19];
assign inst_mulh_wu= op_31_26_d[6'h00] & op_25_22_d[4'h0] & op_21_20_d[2'h1] & op_19_15_d[5'h1a];
assign inst_div_w  = op_31_26_d[6'h00] & op_25_22_d[4'h0] & op_21_20_d[2'h2] & op_19_15_d[5'h00];
assign inst_div_wu = op_31_26_d[6'h00] & op_25_22_d[4'h0] & op_21_20_d[2'h2] & op_19_15_d[5'h02];
assign inst_mod_w  = op_31_26_d[6'h00] & op_25_22_d[4'h0] & op_21_20_d[2'h2] & op_19_15_d[5'h01];
assign inst_mod_wu = op_31_26_d[6'h00] & op_25_22_d[4'h0] & op_21_20_d[2'h2] & op_19_15_d[5'h03];


assign alu_op[ 0] = inst_add_w | inst_addi_w | inst_ld_w | inst_st_w
                    | inst_jirl | inst_bl
                    | inst_pcaddu12i;
assign alu_op[ 1] = inst_sub_w;
assign alu_op[ 2] = inst_slt|inst_slti;
assign alu_op[ 3] = inst_sltu|inst_sltui;
assign alu_op[ 4] = inst_and|inst_andi;
assign alu_op[ 5] = inst_nor;
assign alu_op[ 6] = inst_or|inst_ori;
assign alu_op[ 7] = inst_xor|inst_xori;
assign alu_op[ 8] = inst_slli_w|inst_sll;
assign alu_op[ 9] = inst_srli_w|inst_srl;
assign alu_op[10] = inst_srai_w|inst_sra;
assign alu_op[11] = inst_lu12i_w;

assign need_ui5   =  inst_slli_w | inst_srli_w | inst_srai_w;
assign need_si12  =  inst_addi_w | inst_ld_w | inst_st_w | inst_slti | inst_sltui;
assign need_si16  =  inst_jirl | inst_beq | inst_bne;
assign need_si20  =  inst_lu12i_w | inst_pcaddu12i;
assign need_si26  =  inst_b | inst_bl;
assign src2_is_4  =  inst_jirl | inst_bl;
assign need_si12_zero = inst_ori | inst_xori | inst_andi;

assign imm = src2_is_4 ? 32'h4                      :
             need_si20 ? {i20,12'b0}                :
             need_si12_zero ? {20'b0,i12}           :
/*need_ui5 || need_si12*/{{20{i12[11]}}, i12[11:0]} ;

assign br_offs = need_si26 ? {{ 4{i26[25]}}, i26[25:0], 2'b0} :
                             {{14{i16[15]}}, i16[15:0], 2'b0} ;

assign jirl_offs = {{14{i16[15]}}, i16[15:0], 2'b0};

assign src_reg_is_rd = inst_beq | inst_bne | inst_st_w;

assign src1_is_pc    = inst_jirl | inst_bl | inst_pcaddu12i;

assign src2_is_imm   = inst_slli_w |
                       inst_srli_w |
                       inst_srai_w |
                       inst_addi_w |
                       inst_ld_w   |
                       inst_st_w   |
                       inst_lu12i_w|
                       inst_jirl   |
                       inst_bl     |
                       inst_slti   |
                       inst_sltui  |
                       inst_andi   |
                       inst_ori    |
                       inst_xori   |
                       inst_pcaddu12i;

assign res_from_mem  = inst_ld_w;
assign dst_is_r1     = inst_bl;
assign gr_we         = ~inst_st_w & ~inst_beq & ~inst_bne & ~inst_b;
assign mem_we        = inst_st_w;
assign dest          = dst_is_r1 ? 5'd1 : rd;

assign rf_raddr1 = rj;
assign rf_raddr2 = src_reg_is_rd ? rd :rk;
regfile u_regfile(
    .clk    (clk      ),
    .raddr1 (rf_raddr1),
    .rdata1 (rf_rdata1),
    .raddr2 (rf_raddr2),
    .rdata2 (rf_rdata2),
    .we     (rf_we    ),
    .waddr  (rf_waddr ),
    .wdata  (rf_wdata )
    );

assign rj_value  = read_after_write_addr1[2]? es_alu_result:
                   read_after_write_addr1[1]? ms_final_result:
                   read_after_write_addr1[0]? rf_wdata       :
                                              rf_rdata1      ; 
assign rkd_value = read_after_write_addr2[2]? es_alu_result:
                   read_after_write_addr2[1]? ms_final_result:
                   read_after_write_addr2[0]? rf_wdata       :
                                              rf_rdata2      ; 
assign rj_eq_rd = (rj_value == rkd_value);
assign br_taken =  (  inst_beq  &&  rj_eq_rd
                   || inst_bne  && !rj_eq_rd
                   || inst_jirl
                   || inst_bl
                   || inst_b) && ds_valid && ds_ready_go;
                   
assign br_target = (inst_beq || inst_bne || inst_bl || inst_b) ? (ds_pc + br_offs) :
                                                   /*inst_jirl*/ (rj_value + jirl_offs);
assign alu_src1 = src1_is_pc  ? ds_pc[31:0] : rj_value;
assign alu_src2 = src2_is_imm ? imm : rkd_value;

//EXE stage

reg es_mul_w;
reg es_mulh_w;
reg es_mulh_wu;
reg es_div_w;
reg es_div_wu;
reg es_mod_w;
reg es_mod_wu;

wire [63:0] unsigned_prod, signed_prod;

wire signed_output_valid;
wire unsigned_output_valid;

wire signed_input_valid;
wire signed_s_axis_divisor_tready;
wire signed_s_axis_dividend_tready;
wire [63:0] signed_output_data;
reg [1:0] signed_status;
reg [1:0] signed_next_status;

wire unsigned_input_valid;
wire unsigned_s_axis_divisor_tready;
wire unsigned_s_axis_dividend_tready;
wire [63:0] unsigned_output_data;
reg [1:0] unsigned_status;
reg [1:0] unsigned_next_status;

always @(posedge clk ) begin//EXE reg
if (ds_to_es_valid && es_allowin) begin
    es_alu_op <= alu_op;
    es_res_from_mem <= res_from_mem;
    es_gr_we <= gr_we;
    es_mem_we <= mem_we;
    es_dest <= dest;
    es_rkd_value <= rkd_value;
    es_pc <= ds_pc;
    es_alu_src1 <= alu_src1;
    es_alu_src2 <= alu_src2;
    es_mul_w <= inst_mul_w;
    es_mulh_w <= inst_mulh_w;
    es_mulh_wu <= inst_mulh_wu;
    es_div_w <= inst_div_w;
    es_div_wu <= inst_div_wu;
    es_mod_w <= inst_mod_w;
    es_mod_wu <= inst_mod_wu; 
end
end
assign es_rf_we = es_gr_we & es_valid;
assign es_ready_go = (~(es_div_w | es_mod_w | es_div_wu | es_mod_wu)) | ((es_div_w | es_mod_w) & signed_output_valid) | ((es_div_wu | es_mod_wu) & unsigned_output_valid);
assign es_allowin = (~es_valid)|(es_ready_go & ms_allowin);
assign es_to_ms_valid = es_valid & es_ready_go;

always @(posedge clk) begin
    if (reset) begin     
        es_valid <= 1'b0;
    end
    else if (es_allowin) begin 
        es_valid <= ds_to_es_valid;
    end
end


alu u_alu(
    .alu_op     (es_alu_op    ),
    .alu_src1   (es_alu_src1  ),
    .alu_src2   (es_alu_src2  ),
    .alu_result (alu_result)
    );

assign unsigned_prod = es_alu_src1 * es_alu_src2;
assign signed_prod = $signed(es_alu_src1) * $signed(es_alu_src2);

always @(posedge clk) begin
    if (reset) begin     
        signed_status <= 2'd0;
    end
    else begin 
        signed_status <= signed_next_status;
    end
end

always @(*) begin
	case(signed_status)
		2'd0://waiting inst
			signed_next_status = (es_div_w | es_mod_w) & es_valid ? 2'd1 : 2'd0;
		2'd1://waiting input
			signed_next_status = signed_s_axis_divisor_tready & signed_s_axis_dividend_tready ? 2'd2 : 2'd1;
		2'd2://waiting output
			signed_next_status = signed_output_valid ? 2'd0 : 2'd2;
		default:
			signed_next_status = 2'd3;
	endcase
end
	
assign signed_input_valid = signed_status == 2'd1;

mydiv u_mydiv(
	.aclk (clk),
	.s_axis_divisor_tvalid (signed_input_valid),
	.s_axis_divisor_tready (signed_s_axis_divisor_tready),
	.s_axis_divisor_tdata (es_alu_src2),
	.s_axis_dividend_tvalid (signed_input_valid),
	.s_axis_dividend_tready (signed_s_axis_dividend_tready),
	.s_axis_dividend_tdata (es_alu_src1),
	.m_axis_dout_tvalid (signed_output_valid),
	.m_axis_dout_tdata (signed_output_data)
	);

always @(posedge clk) begin
    if (reset) begin     
        unsigned_status <= 2'd0;
    end
    else begin 
        unsigned_status <= unsigned_next_status;
    end
end

always @(*) begin
	case(unsigned_status)
		2'd0://waiting inst
			unsigned_next_status = (es_div_wu | es_mod_wu) & es_valid ? 2'd1 : 2'd0;
		2'd1://waiting input
			unsigned_next_status = unsigned_s_axis_divisor_tready & unsigned_s_axis_dividend_tready ? 2'd2 : 2'd1;
		2'd2://waiting output
			unsigned_next_status = unsigned_output_valid ? 2'd0 : 2'd2;
		default:
			unsigned_next_status = 2'd3;
	endcase
end
	
assign unsigned_input_valid = unsigned_status == 2'd1;

mydiv_un u_mydiv_un(
	.aclk (clk),
	.s_axis_divisor_tvalid (unsigned_input_valid),
	.s_axis_divisor_tready (unsigned_s_axis_divisor_tready),
	.s_axis_divisor_tdata (es_alu_src2),
	.s_axis_dividend_tvalid (unsigned_input_valid),
	.s_axis_dividend_tready (unsigned_s_axis_dividend_tready),
	.s_axis_dividend_tdata (es_alu_src1),
	.m_axis_dout_tvalid (unsigned_output_valid),
	.m_axis_dout_tdata (unsigned_output_data)
	);

assign es_alu_result = es_mul_w ? unsigned_prod[31:0] :
                      es_mulh_w ? signed_prod[63:32] :
                      es_mulh_wu ? unsigned_prod[63:32] :
                      es_div_w ? signed_output_data[63:32] :
                      es_mod_w ? signed_output_data[31:0] :
                      es_div_wu ? unsigned_output_data[63:32] :
                      es_mod_wu ? unsigned_output_data[31:0] :
                      alu_result;

assign data_sram_addr  = alu_result;
assign data_sram_en = (es_res_from_mem || es_mem_we) && es_valid;
assign data_sram_wdata = es_rkd_value;
assign data_sram_we = {4{es_mem_we}};

//MEM stage

always @(posedge clk ) begin//MEM reg
   if (es_to_ms_valid && ms_allowin) begin
    ms_res_from_mem<=es_res_from_mem;
    ms_alu_result<=es_alu_result;
    ms_gr_we<=es_gr_we;
    ms_dest<=es_dest;
    ms_pc<=es_pc; 
    end
end
assign ms_rf_we = ms_gr_we & ms_valid;
assign ms_ready_go = 1'b1;
assign ms_allowin = (~ms_valid) | (ms_ready_go & ws_allowin);
assign ms_to_ws_valid = ms_valid & ms_ready_go;

always @(posedge clk) begin
    if (reset) begin
        ms_valid <= 1'b0;
    end
    else if (ms_allowin) begin
        ms_valid <= es_to_ms_valid;
    end
end

assign ms_result   = data_sram_rdata;
assign ms_final_result = ms_res_from_mem ? ms_result : ms_alu_result;

//WB stage

reg [ 3:0] ws_sram_we;
always @(posedge clk ) begin //WB reg
if (ms_to_ws_valid && ws_allowin) begin
    ws_gr_we <= ms_gr_we;
    ws_dest <= ms_dest;
    ws_final_result <= ms_final_result;
    ws_pc <= ms_pc;
end
end
assign ws_rf_we = ws_gr_we & ws_valid;
assign ws_ready_go = 1'b1;
assign ws_allowin = (~ws_valid) | ws_ready_go;

always @(posedge clk ) begin
    if (reset) begin
        ws_valid <= 1'b0;
    end
    else if (ws_allowin) begin
        ws_valid <= ms_to_ws_valid;
    end
end

assign rf_we    = ws_gr_we & ws_valid;
assign rf_waddr = ws_dest;
assign rf_wdata = ws_final_result;

// debug info generate
assign debug_wb_pc       = ws_pc;
assign debug_wb_rf_we   = {4{rf_we}};
assign debug_wb_rf_wnum  = ws_dest;
assign debug_wb_rf_wdata = ws_final_result;

endmodule
